#pragma once
#include "log.hpp"
#include "Epoller.hpp"
#include "Socket.hpp"
#include <sys/epoll.h>

static const int PORT = 8080; // 默认端口号
static const int NUM = 64;    // 默认就绪事件数量
class EpollServer
{
public:
    EpollServer(uint16_t port = PORT) : _port(port), _epoller(), _listen_sock()
    {
        _listen_fd = _listen_sock.Socket();
        _listen_sock.Bind(_listen_fd, _port);
        _listen_sock.Listen(_listen_fd);
        LogMessage(DEBUG, "EPOLL INIT SUCCESS LISTEN_FD = %d", _listen_fd);
    }
    void Start()
    {
        // 将_listen_fd添加到epoll中 只关心读事件
        _epoller.EpollUpdata(EPOLL_CTL_ADD, _listen_fd, EPOLLIN);
        // 用于存储就绪的事件。最多可以存储的就绪事件数量。
        struct epoll_event revs[NUM];
        for (;;)
        {
            int n = _epoller.EpollerWait(revs, NUM);
            if (n > 0)
            {
                // 有事件就绪  让事件分配器进行处理
                LogMessage(DEBUG, "event-ready object fd is %d", revs[0].data.fd);
                sleep(1);
                Dispatcher(revs, n);
            }
            else if (n == 0)
            {
                LogMessage(DEBUG, "time out");
            }
            else
            {
                LogMessage(DEBUG, "WAIT FAIL");
            }
        }
    }
    ~EpollServer()
    {
        if (_listen_fd >= 0)
        {
            close(_listen_fd);
        }
    }

private:
    void Dispatcher(struct epoll_event revs[], int num)
    {
        for (int i = 0; i < num; ++i)
        {
            uint32_t event = revs[i].events;
            int fd = revs[i].data.fd;
            if (event & EPOLLIN)
            {
                if (fd == _listen_fd)
                {
                    // 接受客户端的连接请求
                    Accept();
                }
                else
                { 
                    //从套接字中读取信息
                    Recver(fd);
                }
            }
        }
    }
    void Accept()
    {
        std::string ip;
        uint16_t port;
        int sock = _listen_sock.Accept(_listen_fd,&ip,&port);
        if(sock > 0)
        {
            //不能直接从套接字中读取  交给epoll 
            _epoller.EpollUpdata(EPOLL_CTL_ADD,sock,EPOLLIN);
            LogMessage(DEBUG,"GET A NEW LINK # ip = %s port = %d",ip.c_str(),port);
        }
    }
    void Recver(int fd)
    {
        char buffer[1024];//读取缓冲区
        ssize_t read_size = read(fd,buffer,sizeof(buffer));
        if(read_size > 0)
        {
            buffer[read_size-1] = '\0';
            std::cout << "get a message " << buffer << std::endl;

            //回显
            std::string echo_str = "server echo #";
            echo_str += buffer;
            write(fd,echo_str.c_str(),echo_str.size());
        }
        else if(read_size == 0)
        {
            LogMessage(DEBUG,"CLIENT QUIT FD = %d",fd);
            _epoller.EpollUpdata(EPOLL_CTL_DEL,fd,0);
            close(fd);
        }
        else
        {
            LogMessage(DEBUG,"READ FAIL FROM %d",fd);
            _epoller.EpollUpdata(EPOLL_CTL_DEL,fd,0);
            close(fd);
        }
    }

private:
    uint16_t _port;    // 端口号
    Sock _listen_sock; // 套接字
    int _listen_fd;    // 套接字描述符
    Epoller _epoller;  // epoll
};
